package com.ar4j.bench.ar4j.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ar4j.bench.ar4j.domain.Item;
import com.ar4j.bench.ar4j.domain.Product;
import com.ar4j.bench.common.domain.IItem;
import com.ar4j.bench.common.domain.IProduct;
import com.ar4j.bench.common.domain.ProductWithItems;
import com.ar4j.bench.common.service.IProductService;
import com.ar4j.spring.AutowiredAdapter;
import com.ar4j.spring.SpringActiveRecordAdapter;

/**
 * A product service implemented using the AR4J library
 */
@Service
public class ProductAr4jService implements IProductService {
  
  @AutowiredAdapter
  private SpringActiveRecordAdapter<Product> productAdapter;
  
  @Autowired
  private ItemAr4jService itemService;

  @Override
  public Long addProduct(IProduct product) {
    Product theProduct = (Product) product;
    theProduct.save();
    return theProduct.getId();
  }

  @Override
  public Long addProductWithItems(ProductWithItems product) {
    Long productId = addProduct(product.getProduct());
    for(IItem item : product.getItems()) {
      item.setProductId(productId);
      itemService.addItem(item);
    }
    
    return productId;
  }

  @Override
  public List<IProduct> findByCategoryId(Long categoryId) {
    return new ArrayList<IProduct>(productAdapter.readOnly().findAllByCategoryId(categoryId));
  }

  @Override
  public IProduct findById(Long id) {
    return productAdapter.readOnly().findByIdentifier(id);
  }

  @Override
  public List<ProductWithItems> findProductWithItemsByCategoryId(Long categoryId) {
    List<ProductWithItems> out = new ArrayList<ProductWithItems>();
    for(IProduct product : findByCategoryId(categoryId)) {
      ProductWithItems withItems = new ProductWithItems();
      withItems.setProduct(product);
      withItems.setItems(itemService.findByProductId(product.getId()));
      out.add(withItems);
    }
    
    return out;
  }

  @Override
  public ProductWithItems findProductWithItemsById(Long id) {
    ProductWithItems out = new ProductWithItems();
    
    IProduct product = findById(id);
    out.setProduct(product);
    out.setItems(itemService.findByProductId(id));
    
    return out;
  }

  @Override
  public void removeById(Long id) {
    productAdapter.readOnly().deleteByIdentifier(id);    
  }

  @Override
  public void removeProductWithItemsById(Long id) {
    for(IItem item : itemService.findByProductId(id)) {
      Item cur = (Item) item;
      cur.delete();
    }
    
    Product product = (Product) findById(id);
    product.delete();
  }

  @Override
  public void updateProduct(IProduct product) {
    Product theProduct = (Product) product;
    theProduct.save();
  }

  @Override
  public void updateProductWithItems(ProductWithItems product) {
    updateProduct(product.getProduct());
    
    Map<Long, IItem> fromDb = new HashMap<Long, IItem>();
    for(IItem item : itemService.findByProductId(product.getProduct().getId())) {
      fromDb.put(item.getId(), item);
    }
    
    for(IItem item : product.getItems()) {
      if(item.getId() == null || !fromDb.containsKey(item.getId())) {
        itemService.addItem(item);
      } else {
        itemService.updateItem(item);
        fromDb.remove(item.getId());
      }
    }
    
    for(IItem item : fromDb.values()) {
      itemService.removeById(item.getId());
    }
  }

}
